/**********************************************
* @file    	spi_flash.h
* @author 	dralee
* @version	v1.0
* @date			2021-12-08
* @brief		SPI操作FLASH（W25Q64）
***********************************************/
#ifndef __SPI_FLASH_H
#define __SPI_FLASH_H

#include "stm32f10x.h"
#include <stdio.h>

//#define FLASH_ID					0xEF3015				// W25X16
//#define FLASH_ID					0xEF4015				// W25Q16
#define FLASH_ID					0xEF4017				// W25Q64
//#define FLASH_ID					0xEF4018				// W25Q128

#define SPI_FLASH_PageSize						256
#define SPI_FLASH_PerWritePageSize		256

/*****************************************************
* 命令定义
******************************************************/
#define W25X_WriteEnable							0x06
#define W25X_WriteDisable							0x04
#define W25X_ReadStatusReg						0x05
#define W25X_WriteStatusReg						0x01
#define W25X_ReadData									0x03
#define W25X_FastReadData							0x0B
#define W25X_FastReadDual							0x3B
#define W25X_PageProgram							0x02
#define W25X_BlockErase								0xD8
#define W25X_SectorErase							0x20
#define W25X_ChipErase								0xC7
#define W25X_PowerDown								0xB9
#define W25X_ReleasePowerDown					0xAB
#define W25X_DeviceID									0xAB
#define W25X_WManufactDeviceID				0x90
#define W25X_JedecDeviceID						0x9F

// WIP（busy）标志，FLASH内部正在写入
#define WIP_Flag											0x01
#define Dummy_Byte										0xFF

/*****************************************************
* SPI接口定义
******************************************************/
#define FLASH_SPIx										SPI1
#define FLASH_SPI_APBxClock_FUN				RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK									RCC_APB2Periph_SPI1
// CS（NSS）引脚 片选，选择普通GPIO即可
#define FLASH_SPI_CS_APBxClock_FUN		RCC_APB2PeriphClockCmd
#define FLASH_SPI_CS_CLK							RCC_APB2Periph_GPIOC			// CS PC0
#define FLASH_SPI_CS_PORT							GPIOC
#define FLASH_SPI_CS_PIN							GPIO_Pin_0

// SCK引脚
#define FLASH_SPI_SCK_APBxClock_FUN		RCC_APB2PeriphClockCmd
#define FLASH_SPI_SCK_CLK							RCC_APB2Periph_GPIOA			// SCK PA5
#define FLASH_SPI_SCK_PORT						GPIOA
#define FLASH_SPI_SCK_PIN							GPIO_Pin_5
// MISO引脚
#define FLASH_SPI_MISO_APBxClock_FUN	RCC_APB2PeriphClockCmd
#define FLASH_SPI_MISO_CLK						RCC_APB2Periph_GPIOA			// MISO PA6
#define FLASH_SPI_MISO_PORT						GPIOA
#define FLASH_SPI_MISO_PIN						GPIO_Pin_6
// MOSI引脚
#define FLASH_SPI_MOSI_APBxClock_FUN	RCC_APB2PeriphClockCmd
#define FLASH_SPI_MOSI_CLK						RCC_APB2Periph_GPIOA			// MOSI PA7
#define FLASH_SPI_MOSI_PORT						GPIOA
#define FLASH_SPI_MOSI_PIN						GPIO_Pin_7

#define SPI_FLASH_CS_LOW()						GPIO_ResetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN)
#define SPI_FLASH_CS_HIGH()						GPIO_SetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN)

// 等待超时时间
#define SPIT_FLAG_TIMEOUT							((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT							((uint32_t)(10*SPIT_FLAG_TIMEOUT))

// 信息输出
#define FLASH_DEBUG_ON								1
#define FLASH_INFO(fmt,arg...)				printf("<<-FLASH_INFO->>"fmt"\n",##arg)
#define FLASH_ERROR(fmt,arg...)				printf("<<-FLASH_ERROR->>"fmt"\n",##arg)
#define FLASH_DEBUG(fmt,arg...)				do{\
																				if(FLASH_DEBUG_ON)\
																					printf("<<-FLASH_DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
																			}while(0)

void SPI_FLASH_Init(void);
void SPI_FLASH_SectorErase(uint32_t sectorAddr);
void SPI_FLASH_BulkErase(void);
void SPI_FLASH_PageWrite(uint8_t *pBuffer, uint32_t writeAddr, uint16_t numByteToWrite);
void SPI_FLASH_BufferWrite(uint8_t *pBuffer, uint32_t writeAddr, uint16_t numByteToWrite);
void SPI_FLASH_BufferRead(uint8_t *pBuffer, uint32_t readAddr, uint16_t numByteToRead);
uint32_t SPI_FLASH_ReadID(void);
uint32_t SPI_FLASH_ReadDeviceID(void);
void SPI_FLASH_StartReadSequence(uint32_t readAddr);
void SPI_FLASH_PowerDown(void);
void SPI_FLASH_WakeUp(void);
																			
uint8_t SPI_FLASH_ReadByte(void);
uint8_t SPI_FLASH_SendByte(uint8_t byte);
uint16_t SPI_FLASH_SendHalfWord(uint16_t halfWord);
void SPI_FLASH_WriteEnable(void);
void SPI_FLASH_WaitForWriteEnd(void);
																			
#endif
